package com.hrg.rds.biz.traffic;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.hrg.rds.biz.comm.NavService;
import com.hrg.rds.biz.config.RdsConfiguration;
import com.hrg.rds.biz.robot.domain.AgvVo;
import com.hrg.rds.infra.executor.CmdInstanceContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Component("trafficManagement")
@Slf4j
public class TrafficManagement {

	private static final Map<String, AgvVo> AgvIpMap  = RdsConfiguration.AgvIpMap;
	private static final Map<String, TrafficZoneVo> TrafficZoneMap  = RdsConfiguration.TrafficZoneMap;

	/**
	 * 每次重新启动执行器之前检查（Async.beginWorkAsync(ExecutorUtil.wrapWorker(waybillInstanceVo));）
	 * 检查交管不满足时，增加前置执行器用于检查交管是否满足
	 *
	 * @param lockPaths 锁定路线、非当前发送的导航路线
	 * @param agvIp
	 * @return 是否锁定成功
	 */
	synchronized public static boolean tryTrafficControl(List<String> lockPaths, String agvIp, List<String> paths) {

		AgvVo agvVo = AgvIpMap.get(agvIp);
		Map<String, AgvVo> currentStationMap = AgvIpMap.values().stream().filter(agv -> !agv.getIp().equals(agvIp)).collect(Collectors.toMap(AgvVo::getCurrentStation, Function.identity()));
		for (String station : lockPaths) {
			if (currentStationMap.containsKey(station)) {
				String format = String.format("agvId=%s被agvId=%s占用station=%s", agvVo.getId(), currentStationMap.get(station).getId(), station);
				log.warn(format);
				agvVo.setTrafficMsg(format);
				return false;
			}
		}
		List<TrafficZoneVo> traffics = new ArrayList<>();
		List<TrafficZoneVo> trafficZoneVos = TrafficZoneMap.values().stream().toList();
		for (TrafficZoneVo trafficZoneVo : trafficZoneVos) {
			//路线中包含交管区域
			if (!CollUtil.intersection(trafficZoneVo.getStations(), lockPaths).isEmpty()) {
				// 交管区域已被占用
				if (StrUtil.isNotBlank(trafficZoneVo.getAgvId()) && !trafficZoneVo.getAgvId().equals(agvVo.getId())) {
					String format = String.format("agvId=%s被agvId=%s占用交管区域trafficZoneId=%s,trafficZoneName=%s", agvVo.getId(), trafficZoneVo.getAgvId(), trafficZoneVo.getId(), trafficZoneVo.getName());
					log.warn(format);
					agvVo.setTrafficMsg(format);
					return false;
				}
				trafficZoneVo.setAgvId(agvVo.getId());
				trafficZoneVo.setAgvCode(agvVo.getCode());
				trafficZoneVo.setAgvName(agvVo.getName());
				traffics.add(trafficZoneVo);
			}
		}
		Map<String, TrafficZoneVo> trafficZoneIdMap = agvVo.getTrafficZoneIdMap();
		// 移除已占用的交管区域
		Set<String> collect = traffics.stream().map(TrafficZoneVo::getId).collect(Collectors.toSet());
		Iterator<TrafficZoneVo> iterator = trafficZoneIdMap.values().iterator();
		while (iterator.hasNext()) {
			TrafficZoneVo trafficZoneVo = iterator.next();
			if (!collect.contains(trafficZoneVo.getId())) {
				trafficZoneVo.reset();
			}
			iterator.remove();
		}
		// 添加新占用的交管区域
		traffics.forEach(traffic -> trafficZoneIdMap.put(traffic.getId(), traffic));
		// 设置AgvVo中的锁定路线属性和导航路线
		agvVo.setLockStations(lockPaths);
		agvVo.setNavStations(paths);
		return true;
	}

	// 释放交管资源
	synchronized public static void refreshTrafficControl() {
		// 1s 执行一次
		// 释放当前点之前的锁定点和交管区域。无任务时，释放所有锁定点。
		/*if (this.msgReceivedTime.getTime() % 10 == 0) {
			// 10次推送刷新一次
			TrafficManagement.refreshTrafficControl();
		}*/
		for (AgvVo agvVo : AgvIpMap.values()) {
			if (StrUtil.isBlank(agvVo.getWaybillInstanceId())) {
				// 无任务且不在路线上时（防止已经占用交管区域），释放所有锁定点。
				if (!agvVo.getTrafficZoneIdMap().isEmpty()) {
					agvVo.getLockStations().clear();
					agvVo.getNavStations().clear();
					// 重置清空
					agvVo.getTrafficZoneIdMap().values().forEach(TrafficZoneVo::reset);
					agvVo.getTrafficZoneIdMap().clear();
				}
			} else {
				// 清除当前点之前的锁定点和交管区域
				String currentStation = agvVo.getCurrentStation();
				List<String> lockStations = agvVo.getLockStations();
				if (CollUtil.isNotEmpty(lockStations)) {
					int index = lockStations.indexOf(currentStation);
					List<String> subPaths = CollUtil.sub(lockStations, index, lockStations.size());
					agvVo.setLockStations(subPaths);
					Iterator<TrafficZoneVo> iterator = agvVo.getTrafficZoneIdMap().values().iterator();
					while (iterator.hasNext()) {
						TrafficZoneVo trafficZoneVo = iterator.next();
						if (!CollUtil.intersection(trafficZoneVo.getStations(), subPaths).isEmpty()) {
							// 重置交管区域，移除当前车未使用的交管区域
							trafficZoneVo.reset();
							iterator.remove();
						}
					}
				}
			}
		}
	}

	/**
	 * 尝试抢占交管
	 * @param onlyOccupiedToCurrent 是否只占用到当前站点
	 * @param cmdInstanceContext
	 * @param agvVo
	 * @param targetStation 目标站点
	 * @param paths 导航路径
	 */
	synchronized public static boolean tryTraffic(boolean onlyOccupiedToCurrent, CmdInstanceContext cmdInstanceContext, AgvVo agvVo, String targetStation, List<String> paths) {
		// 全局<模板<模板导航，三个优先级。模板暂时没启用

		// 默认占分段
		List<String> lockPaths = paths;
		// 占子任务
		if (!onlyOccupiedToCurrent && RdsConfiguration.OccupiedResourceLevel == 1) {
			// 卸货点结束运单结束？出了卸货点结束。可能需要出了卸货点，通知对方已卸货完成。
			// 根据取卸货点分割子任务，如[x,load,y,unload,z]，则分割为[x,load],[load,unload],[unload,z]
			List<NavVo> navs = cmdInstanceContext.getWaybillInstanceVo().getNavVos().stream().toList();
			int i = navs.size()-1, lockIdx = navs.size()-1;
			for (int j = 0; j < navs.size(); j++) {
				NavVo navVo = navs.get(j);
				if (navVo.getStation().equalsIgnoreCase(targetStation)) {
					if (!navVo.getNavType().equals(NavType.Normal)) {
						lockIdx = j;
						break;
					} else {
						i = j;
					}
				} else if (i < j && !navVo.getNavType().equals(NavType.Normal)) {
					lockIdx = j;
					break;
				}
			}
			lockPaths = NavService.getNavPath(agvVo.getIp(), agvVo.getCurrentStation(), navs.get(lockIdx).getStation());

		}
		// 占固定数量点
		if (!onlyOccupiedToCurrent && RdsConfiguration.OccupiedResourceLevel == 2) {
			lockPaths = paths;
		}
		if (CollUtil.isEmpty(lockPaths)) {
			return false;
		}
		return TrafficManagement.tryTrafficControl(lockPaths, agvVo.getIp(), paths);
	}
}
